package com.linln.admin.system.service;

import com.baidu.unbiz.fluentvalidator.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.linln.common.data.PageSort;
import com.linln.common.utils.FilterUtil;
import com.linln.common.utils.HttpServletUtil;
import com.linln.common.utils.ResultVoUtil;
import com.linln.modules.system.domain.User;
import com.linln.modules.system.repository.BaseRepository;
import com.sun.xml.bind.v2.model.core.ID;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

import org.springframework.context.ApplicationContext;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.servlet.http.HttpServletRequest;

@Service
public class AppService {



    @Autowired
    private ApplicationContext applicationContext;  // 注入 ApplicationContext

    @Autowired
    private ThymeleafViewResolver thymeleafViewResolver;

    @Autowired
    private EntityManager entityManager;

    /**
     *
     * @param repository
     * @param befor
     * @param after
     * @param template
     * @param dataProcessor
     * @return
     */
    public <T>ResponseEntity<?> layTable(JpaSpecificationExecutor repository, Function<Object, Model> befor, Function<Object, Specification> after, String template, Consumer<Page<T>> dataProcessor){

        String output = HttpServletUtil.getParameter("output", null);

        if (output != null && output.equals("layui.table")){

            Specification specification = after.apply("");
            // 分页
            PageRequest page = PageSort.pageRequest(1000000000, "id", Sort.Direction.DESC);

            Page<T> pageResult = repository.findAll(specification, page);
            // 对数据结果进行处理
            dataProcessor.accept(pageResult);
            // 返回分页 JSON 数据
            return ResponseEntity.ok(ResultVoUtil.success("成功", pageResult.getContent(), pageResult.getTotalElements()));

        } else {
            Model model = befor.apply("");
            return ResponseEntity.ok(renderTemplate(model, template));
        }

    }

    /**
     *
     * @param repository
     * @param template  模板
     * @param filter  模板变量
     * @param before  数据更新校验
     * @param handle  数据处理
     * @param after  数据保存后操作
     * @return
     * @throws Exception
     */
    public ResponseEntity<?> form(BaseRepository repository, String template,
                                  Function<Boolean, Model> filter,
                                  BiFunction<Boolean, Object, Model> voHandler,
                                  Function<Object, Result> before,
                                  Function<Object, Serializable> handle,
                                  Consumer<Serializable> after) throws Exception {
        String method = HttpServletUtil.getMethod();

        if (method.equals("GET")) {
            String id = HttpServletUtil.getParameter("id");
            Boolean isEdit = (id != null);

            Model model = filter.apply(isEdit);

            if (isEdit) {
                Object vo = repository.getById(Long.parseLong(id));
                if (vo != null) {
                    model = voHandler.apply(isEdit, vo);
                    model.addAttribute("vo",vo);
                }
            }

            return ResponseEntity.ok(renderTemplate(model, template));
        }

        if (method.equals("POST")) {
            // 保存之前需要验证数据
            Result validate = before.apply("");

            if (!validate.isSuccess()) {
                return ResponseEntity.ok(ResultVoUtil.error(0, String.join(",", validate.getErrors())));
            }

            Serializable entity = handle.apply("");

            repository.save(entity);

            after.accept(entity);

            return ResponseEntity.ok(ResultVoUtil.success("成功"));
        }

        return ResponseEntity.badRequest().body("Unsupported HTTP method");
    }

    public ResponseEntity<?> form(BaseRepository repository, String template,
                                  Function<Boolean, Model> filter,
                                  Function<Object, Result> before,
                                  Function<Object, Serializable> handle,
                                  Consumer<Serializable> after) throws Exception {
        return form(repository, template, filter, (isEdit, vo) -> filter.apply(isEdit), before, handle, after);
    }


    private String renderTemplate(Model model, String template){
        // 必须手动渲染模板
        Context context = new Context();
        // 将数据加入到 Thymeleaf 上下文中
        context.setVariables(model.asMap());
        // 使用 Thymeleaf 渲染模板
        StringWriter writer = new StringWriter();
        thymeleafViewResolver.getTemplateEngine().process(template, context, writer);
        return writer.toString();
    }


    /**
     *
     * @param repository JPA数据库操作对象
     * @param before 数据校验
     * @param handle 数据处理
     * @param after 数据处理后曹祖
     * @return
     */
    public ResponseEntity<?> save(BaseRepository repository, Function<Object, Result> before, Function<Object, Serializable> handle, Consumer<Serializable> after){

        Result validate = before.apply("");

        if (!validate.isSuccess()) {
            return ResponseEntity.ok(ResultVoUtil.error(0, String.join(",", validate.getErrors())));
        }

        Serializable entity = handle.apply("");

        repository.save(entity);

        after.accept(entity);

        return ResponseEntity.ok(ResultVoUtil.success("保存成功"));
    }

}
